#include "serial_utility.hpp"

#include <string.h>


/**
 * @brief 从串口连续读取指定长度的字符，并转换成无符号整数。
 *
 * 只接受0-9 ASCII 字符，出现其他任何字符都返回错误。错误用UINT32_MAX 表示。
 *
 * 函数假设可以无阻塞的从串口读取len 个字符，否则会阻塞等待，如果读取超时，返回错误。
 *
 * @param s
 * @param len
 * @return uint32_t
 */
uint32_t parse_uint_from_serial(HardwareSerial &s, uint8_t len) {
    constexpr uint32_t MAX = ~static_cast<uint32_t>(0);

    // 从串口读取指定长度的整数
    uint32_t value = 0;
    // bool is_negative = false;

    for (uint8_t i = 0; i < len; ++i) {
        auto c = s.read();
        if (c < 0) {
            // 如果读取失败，返回MAX
            return MAX;
        }

        if (value == 0) {
            if (c == '0') {
                // 如果是前导零，继续读取
                continue;
            }
            // else if (c == '-') {
            //     is_negative = true;
            //     continue;
            // }
        }

        if (c < '0' || c > '9') {
            // 如果不是数字字符，返回MAX
            return MAX;
        }

        value = value * 10 + (c - '0');
    }

    return value;
}


/**
 * @brief 从串口输出固定长度的无符号整数。
 *
 * 数字右对齐，左侧填充placeholder 指定的字符，默认为'0'。
 * 将数字按十进制分解后，默认转换为ASCII 字符，
 * 若hex = true，则不转换，直接输出。
 *
 * @param s
 * @param len   最大16
 * @param d
 * @param placeholder
 * @param hex
 */
void print_uint_to_serial(HardwareSerial &s,
                          uint8_t len,
                          uint32_t n,
                          uint8_t placeholder,
                          bool hex) {
    // uint32_t 分解为10进制最多10 位数，多余的部分用来支持len > 10 的情况
    constexpr auto MAX_UINT_LEN = 16;
    char buf[MAX_UINT_LEN];

    if (len > MAX_UINT_LEN) {
        len = MAX_UINT_LEN;
    }

    // 用placeholder 填充缓冲区
    memset(buf, placeholder, MAX_UINT_LEN);
    char *str = &buf[sizeof(buf) - 1];
    auto base = 10;

    do {
        char c = n % base;
        n /= base;
        if (!hex) {
            // 如果hex = true，就不转换ASCII
            c += '0';
        }
        *str = c;
        --str;
    } while (n);

    // 输出缓冲区右侧n 个字节
    for (auto i = MAX_UINT_LEN - len; i < MAX_UINT_LEN; ++i) {
        s.write(buf[i]);
    }
}


void print_hex_table_to_serial(HardwareSerial &s, const uint8_t *arr, size_t table_len, size_t column_count) {
    if (table_len == 0 || arr == nullptr) {
        return;
    }

    if (column_count == 0) {
        column_count = 16;
    }

    auto row_counter = 0;
    for (auto i = 0; i < table_len; ++i) {
        auto d = arr[i];
        if (d < 0x10) {
            // 给不足两位的数在左侧补零
            s.print('0');
        }
        s.print(d, 16);

        if (row_counter == column_count) {
            s.print('\n');
            row_counter = 0;
        }
        else {
            s.print(' ');
            ++row_counter;
        }
    }
    s.println();
}
